#include <machine.h>	/* Platform dependent include file */
#include "iodefine.h"	/* Platform dependent include file */
#include "diskio.h"		/* Common include file for ff.c and disk layer */
#include "ffconf.h"
#include "../DRV_SPI/r_spiflash_driver.h"
#include "../stdio/stdio.h"



#ifdef __LIT
#define LDDW(x) revl(x)	/* Little endian: swap bytes */
#else
#define LDDW(x) x		/* Big endian: no swap */
#endif




static volatile
DSTATUS Stat = STA_NOINIT;	/* Physical drive status */

static volatile
WORD Timer1, Timer2;	/* 1000Hz decrement timer stopped at zero (driven by disk_timerproc()) */
#define	WP			0 	/* Write protect switch (Protected:True, Enabled:False) */


/*-----------------------------------------------------------------------*/
/* Initialize disk drive                                                 */
/*-----------------------------------------------------------------------*/
BYTE init_flag = 0;

DSTATUS disk_initialize (
	BYTE drv		/* Physical drive number (0) */
)
{
	if (drv) return STA_NOINIT;			/* Supports only drive 0 */

	//Stat |= STA_NOINIT;
	//if(!init_flag)	
	if(R_SPIFLASH_Initialise())
	{
		Stat &= ~STA_NOINIT;				/* Clear STA_NOINIT flag */			
		init_flag = 1;
		printf("disk_initialized OKAY !\n");	
		
		R_SPIFLASH_MemoryProtection(false);
	}

	return Stat;	
}



/*-----------------------------------------------------------------------*/
/* Get disk status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE drv		/* Physical drive number (0) */
)
{
	if (drv) return STA_NOINIT;		/* Supports only drive 0 */
	return Stat;	/* Return disk status */
}

/*-----------------------------------------------------------------------*
* 	Read sector(s)                                                        							
*
*	buff: where to read
*	sector: which sector want to read 
*	count: how many bytes want to read
*
*-----------------------------------------------------------------------*/
DRESULT disk_read (
	BYTE drv,		/* Physical drive number (0) */
	BYTE *buff,		/* Pointer to the data buffer to store read data */
	DWORD sector,	/* Start sector number (LBA) */
	BYTE count		/* Number of sectors to read (1..128) */
)
{
	UINT address = 0;
	UINT i = 0;
	UINT bycount = count;
	
	if(drv || (!count)) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* Check if drive is ready */

	/* Bytes addressing conversion, address is the start of sector */
	address = (sector * SSIZE);
	
	printf("Read sector:%04d, address range in: ", sector);
	
	/* One sector - eight pages, one page - 256bytes */
	if(count == 1){	/* READ_SINGLE_BLOCK */				
		if(R_SPIFLASH_Read(buff, address, SSIZE)){
			printf("0x%08x-0x%08x ", address, (address + SSIZE - 1));
			count = 0;
		}
	}else{	/* READ_MULTIPLE_BLOCK */
		do {
			if(!R_SPIFLASH_Read(&buff[0], address, SSIZE))
				break;
			else{
				printf("0x%08x-0x%08x ", address, (address + SSIZE - 1));
			}
			/* Data pointer moved */
			buff += SSIZE;
			/* Address pointer moved */
			address += SSIZE;
		} while (--count);
	}

	if((bycount == 1) || ((bycount > 1) && (count == 0))) printf("success\n");
	
	return count ? RES_ERROR : RES_OK;	/* Return result */
}


/*-----------------------------------------------------------------------*
* 	Read sector(s)                                                        							
*
*	buff: data to write
*	sector: which sector want to write 
*	count: how many bytes want to write
*
*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
	BYTE drv,			/* Physical drive number (0) */
	const BYTE *buff,	/* Ponter to the data to write */
	DWORD sector,		/* Start sector number (LBA) */
	BYTE count			/* Number of sectors to write (1..128) */
)
{
	DWORD address;
    	DWORD i=1000000;
	UINT bycount = count;
	
	if(drv || !count) return RES_PARERR;
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* Check if drive is ready */
	if (Stat & STA_PROTECT) return RES_WRPRT;	/* Check write protect */

	R_SPIFLASH_MemoryProtection(false);

	/* Bytes addressing conversion, address is the start of sector */
	address = (sector * SSIZE);
	printf("Write sector:%04d, address range in: ", sector);
	
	if(count == 1){ /* Single sector write */
		if(erase_4k_sst25v_spiflash(address))
			if(R_SPIFLASH_Write(&buff[0], address, SSIZE)) 
			{
				printf("0x%08x-0x%08x ", address, (address + SSIZE - 1));
				while(i--);
				count = 0;
			}
			else printf("error !\n");
	}else{   /* Multiple sector write */
		do {
			if(!R_SPIFLASH_Write(&buff[0], address, SSIZE))
				break;
			/* Data pointer moved */
			buff += SSIZE;
			/* Address pointer moved */
			address += SSIZE;
		} while (--count);
	}	
	if((bycount == 1) || ((bycount > 1) && (count == 0))) printf("success\n");
	
	return count ? RES_ERROR : RES_OK;	/* Return result */	
}
#endif /* _USE_WRITE */



/*-----------------------------------------------------------------------*/
/* Miscellaneous drive controls other than data read/write               */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl (
	BYTE drv,		/* Physical drive number (0) */
	BYTE ctrl,		/* Control command code */
	void *buff		/* Pointer to the conrtol data */
)
{
	int a;
	DRESULT res = 0;
	BYTE *ptr = buff;

	if (drv) return RES_PARERR;					/* Check parameter */
	if (Stat & STA_NOINIT) return RES_NOTRDY;	/* Check if drive is ready */
	
	res = RES_ERROR;
	switch (ctrl) {
		case CTRL_SYNC :				/* Wait for end of internal write process of the drive */
	  	 	for(a=0;a<100000;a++);
			res = RES_OK;				
			break;

		case GET_SECTOR_COUNT :						/* Get drive capacity in unit of sector (DWORD) */
			*(DWORD*)buff = ( STORAGE_SST25V/SSIZE);	/* 16K sectors in one spi flash */
			res = RES_OK;
			break;

		case GET_SECTOR_SIZE :			/* Get sector size in unit of byte (WORD) */
			*(DWORD*)buff = SSIZE;
			res = RES_OK;
			break;

		case GET_BLOCK_SIZE :			/* Get erase block size in unit of sector (DWORD) */
			*(DWORD*)buff = 1;			/* 4K bytes */
			res = RES_OK;		
			break;
		/* Following command are not used by FatFs module */
		default:
			res = RES_PARERR;
	}

	return res;
}
#endif /* _USE_IOCTL */


/*-----------------------------------------------------------------------*/
/* Device timer function                                                 */
/*-----------------------------------------------------------------------*/
/* This function must be called from system timer process
/  in period of 1 ms to generate card control timing.
*/

void disk_timerproc (void)
{
	WORD n;
	BYTE s;


	n = Timer1;						/* 1kHz decrement timer stopped at 0 */
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;

	s = Stat;
	if (WP)		/* Write protected */
		s |= STA_PROTECT;
	else		/* Write enabled */
		s &= ~STA_PROTECT;
#if 0
	if (INS)	/* Card is in socket */
		s &= ~STA_NODISK;
	else		/* Socket empty */
		s |= (STA_NODISK | STA_NOINIT);
#endif
	Stat = s;
}

